#ifndef _BUFFER_H_
#define _BUFFER_H_

#include "../define/define.h"
#include "../util/lock.h"
#include "../util/timer.h"
#include "../util/log.h"
#include "node.h"

#define define_packet_count  256

class buffer
{
public:
	buffer()
	{
		m_log = new logfile("buffer");

		m_current_id = 0;
		m_big_id     = 0xffffffff;
		m_max_id     = 0xffffffff;

		m_first_id   = 0;
		m_last_id    = 0;

		m_start_id   = 0;
		m_end_id     = 0;

		memset(m_datamap,0xffffffff,sizeof(data_node) * define_packet_count);
	}

	~buffer()
	{
		delete m_log;

		m_current_id = 0;

		m_first_id   = 0;
		m_last_id    = 0;

		m_start_id   = 0;
		m_end_id     = 0;

		memset(m_datamap,0xffffffff,sizeof(data_node) * define_packet_count);
	}

	void set_big_id()
	{
		m_big_id = m_last_id;
		char ll[1024] = {0};
		sprintf(ll,"down over,big_id=%d,last_id=%d",m_big_id,m_last_id);
		m_log->WriteTrace(ll);
	}

	void set_socket(uint32 socket)
	{
         m_s_socket   = socket;
	}

	void reset()
	{
		func_lock lock;

		m_tick = 0;

		m_current_id = 0;

		m_first_id   = 0;
		m_last_id    = 0;

		m_start_id   = 0;
        m_last_id    = 0;
	};

	void create(uint32 current_id,uint32 socket)
	{
		m_current_id = current_id;
		m_s_socket   = socket;

		m_first_id   = current_id;
		m_last_id    = current_id;

		m_start_id   = current_id;
		m_end_id     = current_id;

		memset(m_datamap,0xffffffff,sizeof(data_node) * define_packet_count);
	};

	bool is_full()
	{
		m_lock.EnterLock();

		if(m_last_id - m_first_id >= define_packet_count - 16)
		{
			char tt[1024] ={0};
			sprintf(tt,"is full:m_frist_id=%d,m_last_id=%d,m_start_id=%d,m_end_id=%d",
				m_first_id,m_last_id,m_start_id,m_end_id);
			m_log->WriteTrace(tt);
			
			m_lock.LeaveLock();
			return false;
		}

		m_lock.LeaveLock();
		return true;
	}

	uint32  send_over()
	{
		if(m_big_id == 0xffffffff)
			return 0xffffffff;

		if(m_big_id == m_last_id)
		{
			m_big_id = 0xffffffff;
			m_log->WriteTrace("down over");
			return m_last_id;
		}

		return  0xffffffff;
	}

	uint32 set_last_id(uint32 big_id)
	{
        m_max_id = big_id;

		if(m_max_id != 0xffffffff && m_first_id == m_max_id)
		{
			m_log->WriteTrace("down error");
			return 2;
		}

		return 0;
	}

	uint32 get_packet_id(uint32 count, data_node* nodes,uint32  time_out)
	{
		m_lock.EnterLock();
		uint32 j = 0;

		if(m_first_id > m_last_id )
		{
			char tt[1023]= {0};
			sprintf(tt,"get_error,m_last=%d,m_frist_id=%d",m_last_id,m_first_id);
			m_log->WriteTrace(tt);
			m_lock.LeaveLock();
			return 0;
		}
	
		/*char tt[1023]= {0};
		sprintf(tt,"get_error,m_last=%d,m_frist_id=%d,m_start_id=%d,m_end_id=%d",
			m_last_id,m_first_id,m_start_id,m_end_id);
		m_log->WriteTrace(tt);*/

		for (uint32 i = m_start_id; i< m_last_id ;i++ ) 
		{
		    if(m_datamap[cale(i)].active == 0xffffffff)
				 continue;

			if(m_datamap[cale(i)].date_id == 0xffffffff)
				 continue;

			if(m_datamap[cale(i)].active == 2)
			{
				if(m_tick > m_datamap[cale(i)].req_tick + time_out )
				{
					 /*char tmp_str[1024] = {0};
				     sprintf(tmp_str,"time_out:data_id=%d,m_tick=%d,req_tick=%d,time_out=%d,m_last=%d,m_frist_id=%d,m_start_id=%d,m_end_id=%d",
						 m_datamap[cale(i)].date_id,m_tick,m_datamap[cale(i)].req_tick,m_datamap[cale(i)].time_out,m_last_id,m_first_id,m_start_id,m_end_id);
				     m_log->WriteTrace(tmp_str);*/

					 m_datamap[cale(i)].active = 1;
					 m_datamap[cale(i)].time_out = 200000;
					 m_datamap[cale(i)].req_tick = m_tick;
				}
				else
				  continue;
			}


			if(m_datamap[cale(i)].active == 1)
			{
				if(j==count)
				{
					m_lock.LeaveLock();
					return count;
				}				
				
				nodes[j] = m_datamap[cale(i)];
				
				m_datamap[cale(i)].active = 2;
                m_datamap[cale(i)].req_tick = m_tick;
                m_datamap[cale(i)].time_out = time_out;
				j++;
	
				if(i > m_end_id)
					m_end_id = i + 1;

				/*char tmp_str[1024] = {0};
                sprintf(tmp_str,"get packet:m_last=%d,m_frist_id=%d,m_end_id=%d,i=%d,m_tick=%d,date_size=%d,req_tick=%d,time_out=%d,i=%d,data_id=%x,count=%d",
                 m_last_id,m_first_id,m_end_id,i,m_tick,m_datamap[cale(i)].buf_size,m_datamap[cale(i)].req_tick,m_datamap[cale(i)].time_out,
                 cale(i),m_datamap[cale(i)].date_id,count);
                m_log->WriteTrace(tmp_str);*/
			}
		}

		m_lock.LeaveLock();
		return j;
	};

	bool put_packet(char* buf, uint32 buf_size)
	{
		m_lock.EnterLock();
	
		if(m_last_id - m_first_id > define_packet_count -1)
		{
			char ll[1024] = {0};
			sprintf(ll,"put_packet: m_first_id=%d,m_last=%d",m_first_id,m_last_id);
			m_log->WriteTrace(ll);
			m_lock.LeaveLock();
			return false;
		}

		if(m_first_id <= m_last_id)
		{
			m_datamap[cale(m_last_id)].active = 1;
			m_datamap[cale(m_last_id)].time_out = 200000;
			m_datamap[cale(m_last_id)].req_tick = get_time();
			m_datamap[cale(m_last_id)].date_id  = m_last_id;
			m_datamap[cale(m_last_id)].buf_size = buf_size;
			memcpy(&m_datamap[cale(m_last_id)].buf,buf,buf_size);
		  	
			m_last_id++;

			/*char ll[1024] = {0};
			sprintf(ll,"put_packet: m_first_id=%d,m_last=%d,time=%d,socket=%d",
				m_first_id,m_last_id,get_time(),m_s_socket);
			m_log->WriteTrace(ll);*/

			m_lock.LeaveLock();
			return true;
		}

		m_log->WriteTrace("put_packet error");
		m_lock.LeaveLock();
		return false;
	};

    uint32 add_packet(uint32 id,char* buf, uint32 buf_size)
	{
		m_lock.EnterLock();

		if(m_last_id - m_first_id == define_packet_count -1)
		{
			char ll[1024] = {0};
			sprintf(ll,"add_packet full: m_first_id=%d,m_last=%d",m_first_id,m_last_id);
			m_log->WriteTrace(ll);

			m_lock.LeaveLock();
			return 1;
		}

		if(m_last_id < m_first_id)
		{
			m_log->WriteTrace(" add packet error");
			m_lock.LeaveLock();
			return 1;
		}

		m_datamap[cale(id)].active = 1;
		m_datamap[cale(id)].time_out = 3000;
		m_datamap[cale(id)].req_tick = get_time();
		m_datamap[cale(id)].date_id  = id;
		m_datamap[cale(id)].buf_size = buf_size;
		memcpy(&m_datamap[cale(id)].buf,buf,buf_size);
		
		if(m_last_id < id)
           m_last_id = id + 1;
 
		if(m_last_id == id)
           m_last_id = id + 1;

		/*char ll[1024] = {0};
		sprintf(ll,"add_packet:id=%d,m_first_id=%d,m_last=%d,m_s_socket=%d,m_max_id=%d,buf_size=%d",
			id,m_first_id,m_last_id,m_s_socket,m_max_id,buf_size);
		m_log->WriteTrace(ll);*/

		m_lock.LeaveLock();
 		return 0;
	};

	uint32 del_packet(data_node* node)
	{
        m_lock.EnterLock();
		if(node == NULL)
		{
			m_lock.LeaveLock();
			return 0;
		}

		/*char tmp_str[1024] = {0};
		sprintf(tmp_str,"ack packet:data_id=%d,m_tick=%d,req_tick=%d,time_out=%d,m_last=%d,m_frist_id=%d,m_start_id=%d,m_end_id=%d",
		 node->date_id,m_tick,m_datamap[cale(node->date_id)].req_tick,m_datamap[cale(node->date_id)].time_out,
		 m_last_id,m_first_id,m_start_id,m_end_id);
		m_log->WriteTrace(tmp_str);*/

		uint32 time = m_datamap[cale(node->date_id)].req_tick;
		m_datamap[cale(node->date_id)].date_id = 0xffffffff;
        m_datamap[cale(node->date_id)].active  = 0xffffffff;

        for (uint32 i = m_start_id; i< m_end_id ;i++) 
		{
			if(m_datamap[cale(i)].date_id != 0xffffffff)
                break;

			m_start_id++;
			m_first_id++;
		}	

		m_lock.LeaveLock();
		return time;
	};
	
	uint32 get_current_id()
	{
		m_log->WriteTrace("get_current_id");
		return m_current_id;
	};

	uint32 set_size(uint32 data_id, uint32 size)
	{
		m_lock.EnterLock();

		if(m_datamap[cale(data_id)].buf_size == 0xffffffff)
		{
			m_lock.LeaveLock();
		    return 0;
		}

		if(m_datamap[cale(data_id)].buf_size > size )
		{            
			memcpy(m_datamap[cale(data_id)].buf,m_datamap[cale(data_id)].buf + size,
				m_datamap[cale(data_id)].buf_size -size);

            m_datamap[cale(data_id)].buf_size = m_datamap[cale(data_id)].buf_size -size;
            m_lock.LeaveLock();
		    return 0;
		}

		m_datamap[cale(data_id)].date_id = 0xffffffff;
		m_first_id++;

		if(m_max_id != 0xffffffff && m_first_id == m_max_id)
		{
			char tt[1024] ={0};
			sprintf(tt,"set_size:m_frist_id=%d,m_last_id=%d,m_socket=%d,m_max_id=%d,size=%d",
				m_first_id,m_last_id,m_s_socket,m_max_id,size);
			m_log->WriteTrace(tt);

			m_lock.LeaveLock();
 			return 2;
		}

		m_lock.LeaveLock();
		return 0;
	}

	uint32 read_data(char* buf, uint32* buf_size)
	{
        m_lock.EnterLock();
        uint32    size = 0;
		if( m_first_id >= m_last_id  )
		{
			*buf_size = 0;
			m_lock.LeaveLock();
		    return 3;
		}
		
		for (uint32 i = m_first_id; i< m_last_id ;i++ ) 
		{
			if(size + 1024  > *buf_size)
			{
				*buf_size = size;
				break;
			}

			if(m_datamap[cale(i)].date_id==0xffffffff)
			{
				*buf_size = size;
				m_lock.LeaveLock();
				return 1;
			}
			
			/*char tt[1024] ={0};
			sprintf(tt,"read_data:buf_size=%d,m_frist_id=%d,m_last_id=%d,m_socket=%d,m_max_id=%d,size=%d",
				m_datamap[cale(i)].buf_size,m_first_id,m_last_id,m_s_socket,m_max_id,size);
			m_log->WriteTrace(tt);*/

			memcpy(buf + size,m_datamap[cale(i)].buf,m_datamap[cale(i)].buf_size);
			size = size + m_datamap[cale(i)].buf_size;
		    m_first_id++;
		}

		*buf_size =  size;
		m_lock.LeaveLock();
		return 1;
	}

	uint32 read_data(char* buf, uint32* buf_size,uint32* data_id)
	{
        m_lock.EnterLock();
		if( m_first_id >=m_last_id  )
		{
			/*char ll[1023] = {0};
			sprintf(ll,"read data error,m_first_id=%d,m_last_id=%d,socket=%d,max_id=%d",
				m_first_id,m_last_id,m_s_socket,m_max_id);
			m_log->WriteTrace(ll);*/
			*buf_size = 0;
			m_lock.LeaveLock();
		    return 3;
		}

		if(m_max_id != 0xffffffff && m_first_id == m_max_id)
		{
			char tt[1024] ={0};
			sprintf(tt,"read_data:m_frist_id=%d,m_last_id=%d,m_socket=%d,m_max_id=%d",
				m_first_id,m_last_id,m_s_socket,m_max_id);
			m_log->WriteTrace(tt);

			m_lock.LeaveLock();
 			return 2;
		}
		
		for (uint32 i = m_first_id; i< m_last_id ;i++ ) 
		{

  		   if(m_datamap[cale(i)].date_id==0xffffffff)
			{
			    /*char ll[1023] = {0};
				sprintf(ll,"read no data,m_first_id=%d,m_last_id=%d,socket=%d",
					m_first_id,m_last_id,m_s_socket);
			    m_log->WriteTrace(ll);*/
			    m_lock.LeaveLock();
				return 0;
			}

		    if(m_datamap[cale(i)].buf_size > *buf_size)
			{
				m_log->WriteTrace("read data is error");
				*buf_size = 0;
				m_lock.LeaveLock();
				return 0;
			}

			/*char tt[1024] ={0};
			sprintf(tt,"read_data:i=%d,buf_size=%d,data_id=%d,m_frist_id=%d,m_last_id=%d,m_socket=%d,m_max_id=%d",
				i,m_datamap[cale(i)].buf_size,m_datamap[cale(i)].date_id,m_first_id,m_last_id,m_s_socket,m_max_id);
			m_log->WriteTrace(tt);*/

			memcpy(buf,m_datamap[cale(i)].buf,m_datamap[cale(i)].buf_size);
			*buf_size =  m_datamap[cale(i)].buf_size;
			*data_id = m_datamap[cale(i)].date_id;

			m_lock.LeaveLock();
		    return 1;
		}

		*buf_size = 0;
		m_lock.LeaveLock();
		return 0;
	};

	void set_tick(uint32 tick)
	{
		m_tick = tick;
	};

private:

	uint32 cale(uint32 id)
	{
        return id % define_packet_count;
	};
	
    data_node  m_datamap[define_packet_count];

	uint32     m_tick;

    uint32     m_current_id;
	uint32     m_s_socket;

	uint32     m_start_id;
	uint32     m_end_id;

	uint32     m_first_id;
	uint32     m_last_id;
	
	uint32     m_big_id;
	uint32     m_max_id;

	logfile*   m_log;
	lock       m_lock;
};

#endif
